﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;

namespace Trade.Library.PerformanceTest
{
    public static class CodeTimer
    {
        //int iteration = 1;
        //int iteration = 100 * 1000;
        //string s = "";
        //CodeTimer.Time("String Concat", iteration, () => { s += "a"; });
        //StringBuilder sb = new StringBuilder();
        //CodeTimer.Time("StringBuilder", iteration, () => { sb.Append("a"); });
        //CodeTimer.Time("GetListFromDataTable", iteration, () => GetListFromDataTable());
        //CodeTimer.Time("GetListFromIDataReader", iteration, () => GetListFromIDataReader());
        //CodeTimer.Time("GetPageList", iteration, () => GetPageList());
        //CodeTimer.Time("GetPageListYunNan", iteration, () => GetPageListYunNan());
        //CodeTimer.Time("GetPageDataTable", iteration, () => GetPageDataTable());
        //CodeTimer.Time("GetPageDataTableYunNan", iteration, () => GetPageDataTableYunNan());
        //Console.ReadLine();

        /// <summary>
        /// 初始化
        /// </summary>
        public static void Initialize()
        {
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
            Time("", 1, () => { });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name">测试名称</param>
        /// <param name="iteration">执行次数</param>
        /// <param name="action">测试内容</param>
        public static void Time(string name, int iteration, Action action)
        {
            Time(name, iteration, action, Console.WriteLine);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name">测试名称</param>
        /// <param name="iteration">执行次数</param>
        /// <param name="action">测试内容</param>
        /// <param name="output">输出方式</param>
        public static void Time(string name, int iteration, Action action, Action<string> output)
        {
            if (String.IsNullOrEmpty(name)) return;

            // 1.保留当前控制台前景色，并使用黄色输出名称参数。
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            output(name);

            // 2.强制GC进行收集，并记录目前各代已经收集的次数。
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            int[] gcCounts = new int[GC.MaxGeneration + 1];
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                gcCounts[i] = GC.CollectionCount(i);
            }

            // 3.执行代码，记录下消耗的时间及CPU时钟周期1。
            Stopwatch watch = new Stopwatch();
            watch.Start();
            ulong cycleCount = GetCycleCount();
            for (int i = 0; i < iteration; i++) action();
            ulong cpuCycles = GetCycleCount() - cycleCount;
            watch.Stop();

            // 4.恢复控制台默认前景色，并打印出消耗时间及CPU时钟周期。
            Console.ForegroundColor = currentForeColor;
            output("\t消耗时间:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
            output("\tCPU时钟周期:\t" + cpuCycles.ToString("N0"));

            // 5.打印执行过程中各代垃圾收集回收次数。
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                int count = GC.CollectionCount(i) - gcCounts[i];
                output("\t垃圾回收 " + i + ": \t\t" + count);
            }

            output(string.Empty);
        }

        private static ulong GetCycleCount()
        {
            ulong cycleCount = 0;
            QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);
            return cycleCount;
        }

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentThread();
    }
}
